﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Web;

using MiniTwitter.Extensions;
using MiniTwitter.Properties;

namespace MiniTwitter.Controls
{
    /// <summary>
    /// TextViewer.xaml の相互作用ロジック
    /// </summary>
    public partial class TextViewer : UserControl
    {
        public TextViewer()
        {
            InitializeComponent();
        }

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(TextViewer), new PropertyMetadata(TextPropertyChanged));

        public TextWrapping TextWrapping
        {
            get { return (TextWrapping)GetValue(TextWrappingProperty); }
            set { SetValue(TextWrappingProperty, value); }
        }

        public static readonly DependencyProperty TextWrappingProperty =
            DependencyProperty.Register("TextWrapping", typeof(TextWrapping), typeof(TextViewer), new PropertyMetadata(TextWrapping.Wrap));

        public TextTrimming TextTrimming
        {
            get { return (TextTrimming)GetValue(TextTrimmingProperty); }
            set { SetValue(TextTrimmingProperty, value); }
        }

        public static readonly DependencyProperty TextTrimmingProperty =
            DependencyProperty.Register("TextTrimming", typeof(TextTrimming), typeof(TextViewer), new PropertyMetadata(TextTrimming.None));

        private static void TextPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((TextViewer)sender).OnTextChanged((string)e.NewValue);
        }

        private static readonly Regex searchPattern = new Regex(@"(?<url>https?:\/\/[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+)|@(?<user>[a-zA-Z_0-9]+)\s?|(?<heart><3)|(?<!C)(?<hash>#[^\-\.!~\*'\(\);/\?:@&=\+\$,%# ]+)", RegexOptions.Compiled);

        private void OnTextChanged(string text)
        {
            TextBlock.Inlines.Clear();
            if (text.IsNullOrEmpty())
            {
                return;
            }
            int index = 0;
            foreach (Match match in searchPattern.Matches(text))
            {
                int diff = 0;
                string value = match.Value;
                if (index != match.Index)
                {
                    HighlightKeywords(text.Substring(index, match.Index - index));
                }
                if (value.StartsWith("<3"))
                {
                    Image image = new Image { Width = 14, Height = 14, Margin = new Thickness(1, 0, 1, 0) };
                    image.SetResourceReference(Image.StyleProperty, "HeartImageStyle");
                    TextBlock.Inlines.Add(new InlineUIContainer(image) { BaselineAlignment = BaselineAlignment.Center });
                }
                else if (value.StartsWith("@"))
                {
                    diff = 1;
                    value = match.Groups["user"].Value;
                    Hyperlink link = new Hyperlink { Tag = "http://twitter.com/" + value };
                    link.Inlines.Add(value);
                    link.Click += Hyperlink_Click;
                    TextBlock.Inlines.Add("@");
                    TextBlock.Inlines.Add(link);
                }
                else if (value.StartsWith("#"))
                {
                    Hyperlink link = new Hyperlink { Tag = "http://search.twitter.com/search?q=" + Uri.EscapeDataString(value) };
                    link.Inlines.Add(value);
                    link.Click += Hyperlink_Click;
                    TextBlock.Inlines.Add(link);
                }
                else
                {
                    // URL記法
                    Hyperlink link = new Hyperlink { Tag = value, ToolTip = value };
                    link.ToolTipOpening += new ToolTipEventHandler(Hyperlink_ToolTipOpening);
                    link.Inlines.Add(value);
                    link.Click += Hyperlink_Click;
                    TextBlock.Inlines.Add(link);
                }
                index = match.Index + value.Length + diff;
            }
            if (index != text.Length)
            {
                HighlightKeywords(text.Substring(index));
            }
        }

        private void HighlightKeywords(string text)
        {
            if (Settings.Default.FavoriteRegex == null)
            {
                TextBlock.Inlines.Add(text);
            }
            else
            {
                int startIndex = 0;
                foreach (Match match in Settings.Default.FavoriteRegex.Matches(text))
                {
                    string str = match.Groups[0].Value;
                    if (startIndex != match.Index)
                    {
                        TextBlock.Inlines.Add(text.Substring(startIndex, match.Index - startIndex));
                    }
                    Run item = new Run(" " + str + " ");
                    item.FontWeight = FontWeights.Bold;
                    item.Background = Brushes.Yellow;
                    TextBlock.Inlines.Add(item);
                    startIndex = match.Index + str.Length;
                }
                if (startIndex != text.Length)
                {
                    TextBlock.Inlines.Add(text.Substring(startIndex));
                }
            }
        }

        private static void Hyperlink_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var hyperlink = (Hyperlink)sender;
                var url = (string)hyperlink.Tag;
                Process.Start(url);
            }
            catch
            {
                MessageBox.Show("移動に失敗しました", App.NAME);
            }
        }

        private void Hyperlink_ToolTipOpening(object sender, ToolTipEventArgs e)
        {
            var hyperlink = (Hyperlink)sender;
            if (hyperlink.ToolTip is string)
            {
                var url = (string)hyperlink.Tag;
                hyperlink.ToolTip = null;
                var request = (HttpWebRequest)WebRequest.Create(url);
                request.AllowAutoRedirect = false;
                request.Timeout = 1000;
                request.Method = "HEAD";
                try
                {
                    var response = (HttpWebResponse)request.GetResponse();
                    if (response.StatusCode == HttpStatusCode.MovedPermanently)
                    {
                        var location = response.Headers["Location"];
                        if (!location.IsNullOrEmpty())
                        {
                            hyperlink.ToolTip = new TextBlock { Text = location };
                        }
                    }
                }
                catch { }
                if (hyperlink.ToolTip == null)
                {
                    e.Handled = true;
                }
            }
		}

		#region added by yuki.
		private void GoogleSearchMenuItem_Click(object sender, RoutedEventArgs e) {
			Process.Start(String.Format("http://www.google.co.jp/search?q={0}", HttpUtility.UrlEncode(_viewer.Selection.Text)));
		}
		#endregion
	}
}
